Skip to content

Add support for unified hosts#1307

Merged
jh-db merged 18 commits into
mainfrom
jh-db/unified-hosts
Oct 31, 2025
Merged

Add support for unified hosts#1307
jh-db merged 18 commits into
mainfrom
jh-db/unified-hosts

Conversation

@jh-db

@jh-db jh-db commented Oct 15, 2025

Copy link
Copy Markdown
Contributor

What changes are proposed in this pull request?

This PR adds support for unified hosts, i.e. hosts that support both workspace and account methods. To do this, it:

  • separates client type from host type determination, deprecating isAccountClient and replacing it with HostType and ConfigType.
  • adds an experimental flag to indicate if a host is unified: experimental_is_unified_host
  • adds a WorkspaceId attribute to config, which is necessary for workspace clients that talk to unified hosts
  • adds UnifiedOAuthArgument, which is used in endpoint_supplier.go to discover OAuth endpoints on unified hosts and cache tokens for those hosts.
  • Adds a request visitor which adds an X-Databricks-Org-Id header to requests made by workspace clients

Note: workspace_client.go and account_client.go are generated and will be updated in a separate PR upstream.

How is this tested?

unit & intg tests

@jh-db jh-db temporarily deployed to test-trigger-is October 15, 2025 09:35 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 15, 2025 09:36 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 15, 2025 09:37 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 15, 2025 09:37 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 16, 2025 07:50 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 16, 2025 07:51 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 16, 2025 07:53 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 16, 2025 07:53 — with GitHub Actions Inactive
Comment thread config/api_client.go Outdated
// It relies on the workspace ID being set if and only if a workspace client is being used.
func workspaceOrgIdVisitor(cfg *Config) func(r *http.Request) error {
return func(r *http.Request) error {
if cfg.WorkspaceId != "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: let's check what happens if a user specifies the wrong workspace ID for a given workspace host.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checked, the header is ignored by workspace hosts.

Comment thread config/config.go Outdated
Comment thread config/config.go
Comment thread credentials/u2m/endpoint_supplier.go Outdated
return a.ln.Close()
}

// validateArg ensures that the OAuthArgument is either a WorkspaceOAuthArgument

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update this comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread credentials/u2m/unified_oauth_argument.go Outdated
Comment thread account_client.go Outdated
}

var ErrNotAccountClient = errors.New("invalid Databricks Account configuration")
var ErrWorkspaceIdInAccountClient = errors.New("WorkspaceId must not be set when using AccountClient")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes need to happen in codegen.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will split these out, keeping them in here just for tests & review for now

Comment thread workspace_client.go Outdated
}
if cfg.IsAccountClient() {
hostType := cfg.GetHostType()
if hostType == config.AccountHost || hostType == config.UnifiedHost && cfg.WorkspaceId == "" {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: separate check with a better error message than the (already poor) status quo

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do in codegen

@jh-db jh-db temporarily deployed to test-trigger-is October 24, 2025 14:10 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 24, 2025 14:11 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 24, 2025 15:18 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 24, 2025 15:19 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 24, 2025 15:27 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 24, 2025 15:27 — with GitHub Actions Inactive
@jh-db jh-db requested a review from mgyucht October 27, 2025 13:00
@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 10:45 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 10:46 — with GitHub Actions Inactive
@jh-db jh-db changed the title [WIP] Add support for unified hosts Add support for unified hosts Oct 30, 2025

@mgyucht mgyucht left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few comments/suggestions, let me know what you think

Comment thread config/api_client.go Outdated
},
}

// Workspace IDs must be provided explicitly in request headers when using unified hosts.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: a bit more clarity on this doccomment, for example:

and when calling workspace-level APIs. Furthermore, workspace ID must not be provided when calling account-level APIs.

Comment thread config/auth_azure_msi.go Outdated
if err != nil {
return nil, fmt.Errorf("resolve host: %w", err)
}
err := cfg.azureEnsureWorkspaceUrl(ctx, c)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stupid question: we can use Azure MSI with account-level APIs as well, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but we do various checks that basically ensure that azureEnsureWorkspaceUrl only takes effect if the client is configured for workspace APIs. But just to remove any doubt I've replaced the calls here and in auth_gcp_id with ClientType(). If there's a desire to remove these in the future we can build on the research done here, but we don't need to block this PR on it.

Comment thread config/config.go
// client in the future.
//
// Deprecated: Use HostType() instead.
func (c *Config) ConfigType() ConfigType {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this used?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's needed by Terraform. We could use it in azure_msi and gcp_id auth.

Comment thread config/config.go Outdated
// ConfigType returns the type of config that the client is configured for.
// Returns InvalidConfig if the config is invalid.
// Use of this function should be avoided where possible, because we plan
// to remove WorkspaceClient and AccountClient in favo of a single unified

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// to remove WorkspaceClient and AccountClient in favo of a single unified
// to remove WorkspaceClient and AccountClient in favor of a single unified

Comment thread config/config.go Outdated
// to remove WorkspaceClient and AccountClient in favo of a single unified
// client in the future.
//
// Deprecated: Use HostType() instead.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get the sense that this is deprecated yet, though I do agree that it would be deprecated once we move to the unified API endpoint. Until then, there isn't really an alternative to this, so it doesn't make sense to me to recommend using HostType() directly.

@jh-db jh-db Oct 30, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree. I was trying to discourage usage, but I think marking it as deprecated is too much when there's no viable alternative yet in some cases.

Comment thread config/config.go
Comment thread config/config.go Outdated
}
host := c.CanonicalHostName()
if c.IsAccountClient() {
switch hostType := c.HostType(); hostType {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can pattern match on the result of the assignment without repeating it in Golang

Suggested change
switch hostType := c.HostType(); hostType {
switch hostType := c.HostType() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using it in the error message, but I can just call the function twice if that's preferred?

Comment thread config/config.go Outdated
}
host := c.CanonicalHostName()
if c.IsAccountClient() {
switch hostType := c.HostType(); hostType {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Suggested change
switch hostType := c.HostType(); hostType {
switch hostType := c.HostType() {

// UnifiedOAuthArgument is an interface that provides the necessary information
// to authenticate using OAuth to a host that supports both account and workspace APIs.
type UnifiedOAuthArgument interface {
OAuthArgument

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stupid question: this interface is identical to AccountOAuthArgument, can it just implement that interface instead?

@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 14:13 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 14:14 — with GitHub Actions Inactive
// UnifiedOAuthArgument is an interface that provides the necessary information
// to authenticate using OAuth to a host that supports both account and workspace APIs.
type UnifiedOAuthArgument interface {
OAuthArgument

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, I don't see the use of having an extra interface. We can just document that the AccountOAuthArgument interface can be used whether authenticating to an accounts host or a unified host. If there were a net new behavior that only applied to unified hosts, we could add something like this. So let's remove this (and maybe touch up the documentation on the accounts interface/implementation).

case AccountOAuthArgument:
endpoints, err = a.endpointSupplier.GetAccountOAuthEndpoints(
a.ctx, argg.GetAccountHost(), argg.GetAccountId())
case UnifiedOAuthArgument:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I see what I think is going a bit wrong here. I feel like the OAuthEndpointSupplier should actually be provided as part of the OAuthArgument. That way the PersistantAuth doesn't need to know which EndpointSupplier method to call for a given OAuth argument, and it is fixed per OAuth argument.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, though we can treat this as a follow-up.

Comment thread config/config.go
Comment on lines +353 to +355
if c.AccountID != "" && c.isTesting {
return AccountHost
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if c.AccountID != "" && c.isTesting {
return AccountHost
}
// TODO: Refactor tests so that this is not needed.
if c.AccountID != "" && c.isTesting {
return AccountHost
}

@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 21:59 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 22:00 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 22:04 — with GitHub Actions Inactive
@jh-db jh-db temporarily deployed to test-trigger-is October 30, 2025 22:04 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown

If integration tests don't run automatically, an authorized user can run them manually by following the instructions below:

Trigger:
go/deco-tests-run/sdk-go

Inputs:

  • PR number: 1307
  • Commit SHA: f5d779a046c445c01e3dadd0e00ad6ef8eb7090c

Checks will be approved automatically on success.

@jh-db jh-db added this pull request to the merge queue Oct 31, 2025
Merged via the queue into main with commit 5b291af Oct 31, 2025
15 checks passed
@jh-db jh-db deleted the jh-db/unified-hosts branch October 31, 2025 07:44
github-merge-queue Bot pushed a commit to databricks/databricks-sdk-py that referenced this pull request Dec 17, 2025
## What changes are proposed in this pull request?
This PR adds support for unified host:
- Separates client type from host type determination, deprecating
is_account_client and replacing it with host_type and client_type
properties using new HostType and ClientType
   enums
- Adds an experimental flag to indicate if a host is unified:
experimental_is_unified_host
- Adds a workspace_id attribute to Config, which is necessary for
workspace clients that talk to unified hosts
- Adds get_unified_endpoints() function, which is used in the OIDC
endpoint resolution logic to discover OAuth endpoints on unified hosts
- Adds header injection logic in ApiClient which adds an
X-Databricks-Org-Id header to requests made by workspace clients on
unified hosts
- Adds comprehensive test coverage including unit tests for host/config
type detection, OIDC endpoint resolution, header injection, and
integration tests

Similar to what is done for
databricks/databricks-sdk-go#1307

## How is this tested?
- Unit tests
- Manually integration tested
<img width="1275" height="331" alt="image"
src="https://github.com/user-attachments/assets/f456e104-6210-43a4-a99a-1c2ff0b134a2"
/>
- All existing integration tests pass

Note: Integration test would be added in another PR once the test infra
supports spog
github-merge-queue Bot pushed a commit to databricks/cli that referenced this pull request Jan 21, 2026
## Changes
<!-- Brief summary of your changes that is easy to understand -->
- Add support for unified host with experimental flag. 
- Prompt for workspace id as it's not part of the host
- Write the IDs and flag in the created profile. 
- Depends on databricks/databricks-sdk-go#1307 

## Why
<!-- Why are these changes needed? Provide the context that the reviewer
might be missing. -->
This support is required for enabling unified hosts which Databricks
free edition uses.

## Tests
<!-- How have you tested the changes? -->
- Unit tests
- Manual E2E tests -- CUJ for CLI U2M `databricks auth login --host
<spog-host> --experimental-is-unified-host` prompts for account and
workspace id followed by opening web browser. The IDs and flag is stores
in the config. The subsequent cli operations eg: databricks clusters
list --profile "above-profile" works.
github-merge-queue Bot pushed a commit to databricks/databricks-sdk-java that referenced this pull request Jan 21, 2026
## What changes are proposed in this pull request?

This PR adds support for unified host:

- Separates client type from host type determination, deprecating
`isAccountClient` and replacing it with `getHostType()` and
`getClientType()` methods using new `HostType` and `ClientType` enums
- Adds an experimental flag to indicate if a host is unified:
`experimentalIsUnifiedHost`
- Adds a `workspaceId` attribute to DatabricksConfig, which is necessary
for workspace clients that talk to unified hosts
- Adds `getUnifiedOidcEndpoints()` function, which is used in the OIDC
endpoint resolution logic to discover OAuth endpoints on unified hosts
- Adds header injection logic in DatabricksConfig.authenticate() which
adds an `X-Databricks-Org-Id` header to requests made by workspace
clients on unified hosts
- Adds comprehensive test coverage including unit tests for host/client
type detection, OIDC endpoint resolution, header injection, and
integration tests

Similar to what is done for:
-
[databricks/databricks-sdk-py#1135](databricks/databricks-sdk-py#1135)
-
[databricks/databricks-sdk-go#1307](databricks/databricks-sdk-go#1307)

## How is this tested?
- Unit tests
- Manually E2E tested with a spog profile
denik pushed a commit to databricks/cli that referenced this pull request May 20, 2026
## Changes
<!-- Brief summary of your changes that is easy to understand -->
- Add support for unified host with experimental flag. 
- Prompt for workspace id as it's not part of the host
- Write the IDs and flag in the created profile. 
- Depends on databricks/databricks-sdk-go#1307 

## Why
<!-- Why are these changes needed? Provide the context that the reviewer
might be missing. -->
This support is required for enabling unified hosts which Databricks
free edition uses.

## Tests
<!-- How have you tested the changes? -->
- Unit tests
- Manual E2E tests -- CUJ for CLI U2M `databricks auth login --host
<spog-host> --experimental-is-unified-host` prompts for account and
workspace id followed by opening web browser. The IDs and flag is stores
in the config. The subsequent cli operations eg: databricks clusters
list --profile "above-profile" works.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants